package com.gopay.bis.service.bank.impl.expay;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.bis.dao.bankorder.BankContractInfoDAO;
import com.gopay.bis.manager.bank.expay.CebExPayManager;
import com.gopay.bis.service.bank.sms.SmsSupportController;
import com.gopay.common.Result;
import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.CebContants;
import com.gopay.common.constants.bank.ContractStateConstants;
import com.gopay.common.constants.bank.QueryNeedCertConstants;
import com.gopay.common.constants.bank.YeePayConstants;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.ExPayBaseMessage;
import com.gopay.common.domain.bank.ceb.expay.CebExPayMessage;
import com.gopay.common.domain.bank.ceb.expay.res.CebExpaySuitNSOQRes;
import com.gopay.common.domain.bank.ceb.expay.res.CebExpaySuitNSQRes;
import com.gopay.common.domain.bank.ceb.expay.res.CebExpaySuitPPRes;
import com.gopay.common.domain.bank.ceb.expay.res.CebExpaySuitQSCRes;
import com.gopay.common.domain.bank.ceb.expay.res.CebExpaySuitQUSRes;
import com.gopay.common.domain.bis.BisBankContractInfo;
import com.gopay.common.exception.GopayException;
import com.gopay.common.util.MD5Util;
import com.gopay.remote.bank.ExPayInteractRemoteService;

/**
 * 光大快捷支付实现
 * 
 * @CebExPayServiceImpl.java
 * @author lilili
 */
@Service("cebExpayServiceImpl")
public class CebExPayServiceImpl implements ExPayInteractRemoteService {

    private static Logger logger = LoggerFactory.getLogger(CebExPayServiceImpl.class);

    @Resource(name = "cebExPayManager")
    private CebExPayManager cebExPayManager;

    @Resource(name = "bankContractInfoDAO")
    private BankContractInfoDAO bankContractInfoDAO;

    // 短信验证码处理类
    public SmsSupportController smsController;

    @Override
    public Result certification(ExPayBaseMessage baseMsg) {
        Result result = new Result(false);
        CebExPayMessage message = new CebExPayMessage();
        BeanUtils.copyProperties(baseMsg, message);
        try {
            
            BisBankContractInfo contractInfo = findContractInfo(message);
            if(contractInfo == null){
                logger.error("本地数据库无光大快捷签约记录，发起签约操作，gopayOrderId:"+message.getOrderId());
                result = authBindCard(baseMsg, false); 
            }else if (ContractStateConstants.CONTRACT_STATE_FALSE.equals(contractInfo.getContractState())) {
                logger.error("本地数据库中光大快捷签约记录为失效（已解约）状态，发起签约操作，gopayOrderId:"+message.getOrderId());
                result = authBindCard(baseMsg, true);
            } else {
                logger.error("本地数据库存在有效的光大快捷签约记录，进行信息对比判断，gopayOrderId:"+message.getOrderId());
                result = verifyElements(message, contractInfo);
            }
        } catch (GopayException e) {
            BankLogUtils.printServiceImplExceptionLog(e);
            result.setResultCode(e.getErrCode());
        } catch (Exception ex) {
            BankLogUtils.printServiceImplExceptionLog(ex);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100E6076);
        }
        return result;
    }

    /**
     * 发送短信请求
     */
    @Override
    public Result sendSms(ExPayBaseMessage baseMsg) {
        Result result = new Result(false);
        CebExPayMessage message = new CebExPayMessage();
        BeanUtils.copyProperties(baseMsg, message);
        try {
            Map<String, String> smsRes = smsController.sendSMS(message);
            if (ProcCodeConstants.PROC_CODE_100E6102.equals(smsRes.get("resCode"))) {
                // 短信发送成功
                result.setModel("flag", true);
            } else {
                // 短信发送失败
                result.setModel("flag", false);
            }
            result.setModel("sendCount", smsRes.get("sendCount"));
            result.setModel("retMsg", smsRes.get("retMsg"));
            result.setModel("resCode", smsRes.get("resCode"));
            result.setResultCode(smsRes.get("resCode"));
            result.setSuccess(true);
        } catch (Exception ex) {
            BankLogUtils.printServiceImplExceptionLog(ex);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100E6077);
        }
        return result;
    }

    /**
     * 验证短信请求
     */
    @Override
    public Result checkSms(ExPayBaseMessage baseMsg) {
        Result result = new Result(false);
        CebExPayMessage message = new CebExPayMessage();
        BeanUtils.copyProperties(baseMsg, message);
        try {
            Map<String, String> smsRes = smsController.checkSMS(message);
            if (ProcCodeConstants.PROC_CODE_100E6091.equals(smsRes.get("resCode"))) {
                // 验证通过
                result.setModel("flag", true);
            } else {
                // 验证失败
                result.setModel("flag", false);
                if (!ProcCodeConstants.PROC_CODE_100E6099.equals(smsRes.get("resCode"))) {
                    Map<String, String> freezeRes = smsController.freezeCard(message);
                    if (freezeRes != null)
                        smsRes = freezeRes;
                }
            }
            result.setModel("failCount", smsRes.get("failCount"));
            result.setModel("retMsg", smsRes.get("retMsg"));
            result.setModel("resCode", smsRes.get("resCode"));
            result.setResultCode(smsRes.get("resCode"));
            result.setSuccess(true);
        } catch (Exception ex) {
            BankLogUtils.printServiceImplExceptionLog(ex);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100E6078);
        }
        return result;
    }

    @Override
    public Result payment(ExPayBaseMessage baseMsg) {
        Result result = new Result(false);
        CebExPayMessage message = new CebExPayMessage();
        BeanUtils.copyProperties(baseMsg, message);
        try {
            CebExpaySuitPPRes res = (CebExpaySuitPPRes) cebExPayManager.payment(message);
            result.setDefaultModel(res.isSuccess());
            Map<String, String> param = new HashMap<String, String>();
            if (res.isSuccess() && CebContants.EXPAY_PAYMENT_CHECKMSGFLAG_NO
                    .equals(res.getMessage().getPlain().getCheckMsgFlag())) {
                // 验签成功&&不进行短信校验
                param.put("orderId", res.getMessage().getPlain().getSerialNo());
                param.put("amt", res.getMessage().getPlain().getAmount().toString());
                param.put("cardType", "Unknown");
                param.put("notifyNum", "1");
                param.put("payStatus", "00");
                param.put("retCode", "00");
                param.put("retMsg", "验签成功");
                param.put("isFront", String.valueOf(false));
                result.setModel("isNotifyCashier", param);
                result.setSuccess(true);
                result.setOrderStatus(true);
            } else {
                if(res.isSuccess()&&res.getMessage().getPlain().getErrorCode() != null && "1628".equals(res.getMessage().getPlain().getErrorCode())){
                    //签约协议号不正确 ，更改签约状态
                    updateContractState(baseMsg, ContractStateConstants.CONTRACT_STATE_FALSE);
                }
                param.put("orderId", baseMsg.getOrderId());
                param.put("amt", baseMsg.getAmount().toString());
                param.put("cardType", "Unknown");
                param.put("notifyNum", "1");
                param.put("payStatus", "01");
                param.put("retCode", "01");
                // 记录数据库失败信息 add by zhengxue 20170313
                param.put("retMsg", StringUtils.isEmpty(res.getReturnInfo()) ? "交易失败" : res.getReturnInfo());
                param.put("isFront", String.valueOf(false));
                result.setModel("isNotifyCashier", param);
                result.setSuccess(true);
                result.setOrderStatus(false);
                result.setBankRetCode(res.getBankRetCode());//add by liuyu, 20170802, 快捷API失败通知
            }
        } catch (GopayException e) {
            BankLogUtils.printServiceImplExceptionLog(e);
            result.setResultCode(e.getErrCode());
        } catch (Exception ex) {
			BankLogUtils.printServiceImplExceptionLog(ex);
			result.setResultCode(ProcCodeConstants.PROC_CODE_100E6057);
		}
        return result;
    }

    @Override
    public Result queryOrder(ExPayBaseMessage baseMsg) {
        Result result = new Result(false);
        CebExPayMessage message = new CebExPayMessage();
        BeanUtils.copyProperties(baseMsg, message);
        try {
            CebExpaySuitNSOQRes res = (CebExpaySuitNSOQRes) cebExPayManager.query(message);
            if(res.isSuccess()&& null != res.getMessage().getPlain()){
                result.setDefaultModel(res.getMessage().getPlain());
            }
            result.setBankRetCode(res.getBankRetCode());//add by liuyu, 20170802, 快捷API失败通知
            result.setSuccess(true);
        } catch (GopayException e) {
            BankLogUtils.printServiceImplExceptionLog(e);
            result.setResultCode(e.getErrCode());
        } catch (Exception ex) {
			BankLogUtils.printServiceImplExceptionLog(ex);
			result.setResultCode(ProcCodeConstants.PROC_CODE_100E6058);
		}
        return result;
    }

    @Override
    public Result queryCvn(ExPayBaseMessage baseMsg) {
        Result result = new Result();
        result.setSuccess(true);
        result.setModel("flag", true);
        result.setModel("isQueryCVN", YeePayConstants.YEEPAY_EXPAY_ISQUERYCVN);
        return result;
    }

    /**
     * 查询是否需要调用鉴权接口
     */
    public Result queryNeedCert(ExPayBaseMessage baseMsg) {
        Result result = new Result();
        result.setSuccess(true);
        CebExPayMessage message = new CebExPayMessage();
        BeanUtils.copyProperties(baseMsg, message);
        try {
            CebExpaySuitNSQRes queryCert = (CebExpaySuitNSQRes) cebExPayManager.queryCert(message);
            BisBankContractInfo contractInfo = findContractInfo(message);
            if (queryCert.isSuccess() && (null != contractInfo)) {
                String certStatus = queryCert.getMessage().getPlain().getStatus();
                if (CebContants.EXPAY_QUERY_SIGN_SUCCESS.equals(certStatus)
                        && ContractStateConstants.CONTRACT_STATE_SUCCESS.equals(contractInfo.getContractState())) {
                    result.setModel("NeedMark", QueryNeedCertConstants.QUERY_RESULT_NONEED);
                } else {
                    result.setModel("NeedMark", QueryNeedCertConstants.QUERY_RESULT_NEED);
                }
            } else {
                result.setModel("NeedMark", QueryNeedCertConstants.QUERY_RESULT_NEED);
            }
        } catch (GopayException e) {
            BankLogUtils.printServiceImplExceptionLog(e);
            result.setResultCode(e.getErrCode());
        } catch (Exception ex) {
            BankLogUtils.printServiceImplExceptionLog(ex);
            result.setResultCode(ProcCodeConstants.PROC_CODE_100E6076);
        }
        return result;

    }

    @Override
    public Result verify(ExPayBaseMessage baseMsg) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Result treatyQuery(ExPayBaseMessage baseMsg) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Result cancel(ExPayBaseMessage baseMsg) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Result refund(ExPayBaseMessage baseMsg) {
        // TODO Auto-generated method stub
        return null;
    }

    public void setCebExPayManager(CebExPayManager cebExPayManager) {
        this.cebExPayManager = cebExPayManager;
    }

    public SmsSupportController getSmsController() {
        return smsController;
    }

    public void setSmsController(SmsSupportController smsController) {
        this.smsController = smsController;
    }

    @Override
    public Result sign(ExPayBaseMessage baseMsg) {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public Result refundBack(ExPayBaseMessage baseMsg) {
        // TODO Auto-generated method stub
        return null;
    }

    /**
     * 根据卡号和签约银行查询生效签约记录
     * 
     * @param message
     * @return
     */
    public BisBankContractInfo findContractInfo(ExPayBaseMessage message) {
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setCardNo(message.getCardNo());
        bisBankContractInfo.setBankBizProdCode(message.getBankBusProd().value);
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        return bankContractInfoDAO.getContractInfoByCard(bisBankContractInfo);
    }

    /**
     * 新建鉴权绑卡信息
     * 
     * @param message
     * @param bindCardId
     *            银行返回绑卡ID
     * @return
     */
    public void newContract(ExPayBaseMessage message, String bindCardId) {
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setBankBizProdCode(message.getBankBusProd().value);
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        bisBankContractInfo.setCardNo(message.getCardNo());
        bisBankContractInfo.setContractState(ContractStateConstants.CONTRACT_STATE_SUCCESS);
        bisBankContractInfo.setContractNumber(bindCardId);
        String verifyCode = createVerificationCode(message);
        // 保存四要素校验码
        bisBankContractInfo.setVerificationCode(verifyCode);
        bisBankContractInfo.setContractNumber(bindCardId);
        bankContractInfoDAO.insertBisBankContractInfo(bisBankContractInfo);
    }

    /**
     * 根据用户输入的四要素/六要素创建校验码
     * 
     * @param message
     * @return
     */
    public String createVerificationCode(ExPayBaseMessage message) {
        StringBuffer msg = new StringBuffer();
        // 信用卡 增加CVN2和有效期两要素
        if (BisBankBusinessProd._05.value.equals(message.getBankBusProd().value)) {
            msg.append(message.getCvv2());
            msg.append(message.getAvailableDate());
        }
        msg.append(message.getCardHolder());
        msg.append(message.getCardNo());
        msg.append(message.getIdentityCode());
        msg.append(message.getMediaId());
        return MD5Util.sign(msg.toString());
    }

    /**
     * 根据卡号，产品码，通道，修改签约信息的签约状态，协议码
     * 
     * @param message
     * @param bindCardId
     * @param constractState
     * @author w_jiqing
     */
    public void updateContractInfo(ExPayBaseMessage message, String bindCardId, String constractState, boolean flag) {
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setContractState(constractState);
        bisBankContractInfo.setCardNo(message.getCardNo());
        bisBankContractInfo.setContractNumber(bindCardId);
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setBankBizProdCode(message.getBankBusProd().value);
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        if (flag) {
            String verifyCode = createVerificationCode(message);
            // 保存四要素校验码
            bisBankContractInfo.setVerificationCode(verifyCode);
        }
        bankContractInfoDAO.updateContractInfoByProdChannelCode(bisBankContractInfo);
    }

    /**
     * 根据绑卡ID修改鉴权绑卡生效状态
     * 
     * @param message
     * @param bindCardId
     *            绑卡ID
     * @param state
     *            签约状态
     * @return
     */
    public void updateContractState(ExPayBaseMessage message, String constractState) {
        BisBankContractInfo bisBankContractInfo = new BisBankContractInfo();
        bisBankContractInfo.setContractState(constractState);
        bisBankContractInfo.setCardNo(message.getCardNo());
        bisBankContractInfo.setBankCode(message.getBank());
        bisBankContractInfo.setBankBizProdCode(message.getBankBusProd().value);
        bisBankContractInfo.setIntrfaceChannelCode(message.getBankIntrChann().value);
        bankContractInfoDAO.updateContractState(bisBankContractInfo);
    }

    /**
     * 签约操作
     * 
     * @param baseMsg
     * @param hasContract
     *            是否存在签约记录
     * @return
     * @throws GopayException
     * @author w_jiqing
     */
    public Result authBindCard(ExPayBaseMessage baseMsg, boolean hasContract) throws GopayException {
        Result result = new Result(false);
        result.setModel("flag", false);
        CebExPayMessage message = new CebExPayMessage();
        BeanUtils.copyProperties(baseMsg, message);
        CebExpaySuitQUSRes certRes = (CebExpaySuitQUSRes) cebExPayManager.certification(message);
        if (certRes.isSuccess()
                && CebContants.EXPAY_SIGN_SUCCESS.equals(certRes.getMessage().getPlain().getSysRtnCd())) {
            String signNo = certRes.getMessage().getPlain().getSignNo();
            // 签约成功
            if (hasContract) {
                // 存在签约记录
                updateContractInfo(message, signNo, ContractStateConstants.CONTRACT_STATE_SUCCESS, true);
                logger.info("光大快捷支付卡号：" + LoggerMaskUtils.maskString(message.getCardNo()) + ",重新签约成功,更新签约信息");
            } else {
                newContract(message, signNo);
                logger.info("光大快捷支付卡号：" + LoggerMaskUtils.maskString(message.getCardNo()) + "签约成功,新建签约信息");
            }
            result.setModel("flag", true);
            result.setSuccess(true);
        }
        return result;
    }

    /**
     * 校验用户信息，信息对比一致，校验通过；对比不一致，解约，重新发起签约
     * 
     * @param baseMsg
     * @param contractInfo
     * @param signNo
     * @return
     * @throws GopayException
     * @author w_jiqing
     */
    public Result verifyElements(ExPayBaseMessage baseMsg, BisBankContractInfo contractInfo)
            throws GopayException {
        Result result = new Result(false);
        result.setModel("flag", false);
        CebExPayMessage message = new CebExPayMessage();
        BeanUtils.copyProperties(baseMsg, message);
        String verifyCode = createVerificationCode(message); // 创建四要素校验码
        if (StringUtils.equals(verifyCode, contractInfo.getVerificationCode())) { // 比较四要素校验码是否匹配
            logger.info("光大快捷支付，gopayOrderId:" + message.getOrderId() + ",已签约且要素匹配,鉴权通过");
            result.setModel("flag", true);
            result.setSuccess(true);
        } else {
            logger.info("光大快捷支付，卡号:" + LoggerMaskUtils.maskString(message.getCardNo()) + ",已签约但签约信息不匹配,需解约。");
            CebExpaySuitQSCRes cancelRes = (CebExpaySuitQSCRes) cebExPayManager.UnBindCard(message, contractInfo.getContractNumber());
            if (cancelRes.isSuccess()&& CebContants.EXPAY_SIGN_SUCCESS.equals(cancelRes.getMessage().getPlain().getSysRtnCd())) {
                updateContractState(message, ContractStateConstants.CONTRACT_STATE_FALSE);
                logger.info("光大快捷支付，卡号:" + LoggerMaskUtils.maskString(message.getCardNo()) + ",解约成功。");
                result = authBindCard(message, true); // 重新签约
            }else{
                logger.info("光大快捷支付，卡号:" + LoggerMaskUtils.maskString(message.getCardNo()) + ",解约失败。");
            }
                
        }
        return result;

    }

}
